/*
 * Copyright (c) 2025 EasyAdmin
 * All rights reserved.
 *
 * This file is part of the [EasAdmin] project.
 * Unauthorized copying of this file, via any medium, is strictly prohibited.
 * Proprietary and confidential.
 *
 * Author: EasyAdmin ( 1073602@qq.com )
 * Website: https://www.xhxiao.com
 */
package com.easy.module.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easy.framework.common.exception.ServiceException;
import com.easy.framework.common.utils.*;
import com.easy.framework.security.annotation.DataScope;
import com.easy.framework.security.utils.SecurityUtils;
import com.easy.module.system.entity.SysUser;
import com.easy.module.system.entity.SysUserDept;
import com.easy.module.system.entity.SysUserRole;
import com.easy.module.system.mapper.SysRoleMapper;
import com.easy.module.system.mapper.SysUserMapper;
import com.easy.module.system.mapper.SysUserRoleMapper;
import com.easy.module.system.query.SysUserQuery;
import com.easy.module.system.service.ISysPostService;
import com.easy.module.system.service.ISysUserDeptService;
import com.easy.module.system.service.ISysUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * 用户表 Service业务
 *
 * @author EasyAdmin ( 1073602@qq.com )
 * @date 2025-08-19
 */
@RequiredArgsConstructor
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {

    private final SysRoleMapper sysRoleMapper;

    private final ISysPostService postService;

    private final SysUserRoleMapper userRoleMapper;

    private final ISysUserDeptService userDeptService;

    @Override
    @DataScope(userAlias = "sys_user", userIdName = "id")
    public List<SysUser> queryList(SysUserQuery query) {
        Optional<LambdaQueryWrapper<SysUser>> optional = lambdaQueryOptional(query);
        optional.ifPresent(w ->
                w.apply(Func.isNotEmpty(query.getDeptId()), StringUtil.format(" (sys_user.id in (select distinct ud.user_id from sys_dept d join sys_user_dept ud on d.id = ud.dept_id  where d.id = {} or  find_in_set({}, ancestors)))", query.getDeptId(), query.getDeptId()))
                .apply(Func.isNotEmpty(query.getDataScope()), query.getDataScope()));
        return list(optional.orElse(null));
    }


    /**
     * 新增用户信息
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean add(SysUser user) {
        AssertUtil.isNotEmpty(user.getDeptId(), "请选择所在的部门或岗位");
        AssertUtil.isNotEmpty(user.getPostIds(), "请选择所在的部门或岗位");
        // 新增用户信息
        boolean sign = save(user);
        for (Long postId : user.getPostIds()) {
            SysUserDept sysUserDept = new SysUserDept();
            sysUserDept.setUserId(user.getId());
            sysUserDept.setDeptId(user.getDeptId());
            sysUserDept.setPostId(postId);
            userDeptService.addUserDept(sysUserDept);
        }
        // 新增用户与角色管理
        insertUserRole(user);
        return sign;
    }

    /**
     * 新增用户角色信息
     *
     * @param user 用户对象
     */
    public void insertUserRole(SysUser user) {
        this.insertUserRole(user.getId(), user.getRoleIds());
    }

    /**
     * 新增用户角色信息
     *
     * @param userId  用户ID
     * @param roleIds 角色组
     */
    public void insertUserRole(Long userId, List<Long> roleIds) {
        if (Func.isNotEmpty(roleIds)) {
            // 新增用户与角色管理
            List<SysUserRole> list = new ArrayList<SysUserRole>(roleIds.size());
            for (Long roleId : roleIds) {
                SysUserRole ur = new SysUserRole();
                ur.setUserId(userId);
                ur.setRoleId(roleId);
                list.add(ur);
            }
            userRoleMapper.addBatch(list);
        }
    }

    /**
     * 修改用户信息
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(SysUser user) {
        Long userId = user.getId();
        // 删除用户与角色关联
        userRoleMapper.deleteByUserId(userId);
        // 新增用户与角色管理
        insertUserRole(user);
        SysUser entity = ConvertUtil.convert(user, SysUser.class);
        return updateById(entity);
    }

    /**
     * 批量删除用户信息
     *
     * @param userIds 需要删除的用户信息主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteByIds(Long... userIds) {
        for (Long userId : userIds) {
            validateAllowed(userId);
        }
        // 删除用户与角色关联
//        userRoleMapper.deleteBatchByUserIds(userIds);
        return removeBatchByIds(List.of(userIds));
    }

    /**
     * 校验是否允许操作
     *
     * @param userId 用户信息
     */
    @Override
    public void validateAllowed(Long userId) {
        AssertUtil.isNotNull(userId, "用户不存在");
        if (SecurityUtils.isAdmin(userId)) {
            throw new ServiceException("不允许操作超级管理员用户");
        }
        validateDataScope(userId);
    }


    /**
     * 校验用户数据范围权限
     *
     * @param userId 用户id
     */
    @Override
    public void validateDataScope(Long userId) {
        if (!SecurityUtils.isAdmin()) {
            SysUserQuery query = new SysUserQuery();
            query.setId(userId);
            List<SysUser> users = SpringUtils.getAopProxy(this).queryList(query);
            if (Func.isEmpty(users)) {
                throw new ServiceException("没有权限访问用户数据！");
            }
        }
    }


    @Override
    public SysUser getByUsername(String username) {
        return getOne(lambdaQueryWrapper().eq(SysUser::getUsername, username), false);
    }

    @Override
    public boolean updatePassword(Long userId, String newPassword) {
        SysUser user = new SysUser();
        user.setId(userId);
        user.setPassword(newPassword);
        return updateById(user);
    }

    @Override
    public boolean updateStatus(Long userId, Integer status) {
        SysUser user = new SysUser();
        user.setId(userId);
        user.setStatus(status);
        return update(user);
    }
}
